﻿#region using statements

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

using NGen;
using NGen.Managers.GameObject;
using NGen.Systems.StringAlarms;

using TowerDefense.Misc;
using TowerDefense.Objects.Enemies;

#endregion

namespace TowerDefense.Objects.Towers
{
	/// <summary>
	/// 	Base class which defines the standard shared tower behavior
	/// </summary>
	public abstract class GameObjectTowerBase : GameObject2D, IAlarmListener
	{
		#region local constants

		/// <summary>
		/// 	the path to the tower textures
		/// </summary>
		protected readonly string m_texturePath = "Content\\Textures\\Towers\\";

		#endregion

		#region local fields

		/// <summary>
		/// 	alarm system which governs local alarm events
		/// </summary>
		protected AlarmSystem m_alarm = new AlarmSystem();

		/// <summary>
		/// 	is this towers' attack on cooldown
		/// </summary>
		protected bool m_attackReady = true;

		/// <summary>
		/// 	enemy this tower is targetting
		/// </summary>
		protected GameObjectEnemyBase m_currentTarget;

		/// <summary>
		/// 	should the attack radius be dispalyed
		/// </summary>
		protected bool m_drawAttackRadius = true;

		/// <summary>
		/// 	color value used to color the circle which shows the tower
		/// 	attack radius
		/// </summary>
		protected Color m_elementColor;

		#endregion

		#region local static fields

		/// <summary>
		/// 	The texture used to display the attack radius of a twoer
		/// </summary>
		public static Texture2D m_attackRadiusTexture;

		#endregion

		#region local properties

		/// <summary>
		/// 	Get the current enemy this tower is targetting
		/// </summary>
		public GameObjectEnemyBase CurrentTarget {
			get { return m_currentTarget; }
		}

		/// <summary>
		/// 	Get the cost to upgrade this tower to the next level.
		/// </summary>
		public int CostToUpgrade { get; protected set; }

		/// <summary>
		/// 	Get the amount of gold returned if this tower is sold
		/// </summary>
		public int SellPrice { get; protected set; }

		/// <summary>
		/// 	Get the current level of this tower
		/// </summary>
		public int TowerLevel { get; protected set; }

		/// <summary>
		/// 	Get the amount of damage this tower deals
		/// </summary>
		public int AttackDamage { get; protected set; }

		/// <summary>
		/// 	Get the amount of attack damage gained per upgrade
		/// </summary>
		public int AttackDamageIncreasePerLevel { get; protected set; }

		/// <summary>
		/// 	Get the time delay between attacks
		/// </summary>
		public float AttackDelay { get; protected set; }

		/// <summary>
		/// 	Get the amount of attack delay decreased per upgrade
		/// </summary>
		public float AttackDelayDecreasePerLevel { get; protected set; }

		/// <summary>
		/// 	Get the attack range of this tower
		/// </summary>
		public float AttackRange { get; protected set; }

		/// <summary>
		/// 	Get the amount of attack range gained per upgrade
		/// </summary>
		public float AttackRangeIncreasePerLevel { get; protected set; }

		/// <summary>
		/// 	Get or set whether this tower is selected or not
		/// </summary>
		public bool Selected {
			get { return m_drawAttackRadius; }
			set {
				m_drawAttackRadius = value;
				m_textureTint = value ? Color.DimGray : Color.White;
				m_zDepth = value ? 0.9f : 0.7f;
			}
		}

		/// <summary>
		/// 	Get or set the position of this tower coordinates relative to 
		/// 	the world tiles
		/// </summary>
		public Point ArrayPosition { get; set; }

		#endregion

		#region local methods

		/// <summary>
		/// 	Called when the tower upgrade button is clicked
		/// </summary>
		public abstract void UpgradeTowerLevel();

		/// <summary>
		/// 	Called when the tower upgrade button is clicked
		/// </summary>
		public abstract void FireAtTarget();

		/// <summary>
		/// 	Called while the tower is being placed, following the mouse
		/// 	cursor around
		/// </summary>
		public void WhilePlacing() {
			_Draw(null);
		}

		#endregion

		#region IAlarmListener implementation

		/// <summary>
		/// 	Receives the callbacks from the alarm system
		/// </summary>
		/// <param name = "p_message">alarm message to pass</param>
		public virtual void OnAlarmEvent(string p_message) {
			switch(p_message) {
				case "attackReady":
					m_attackReady = true;
					break;
			}
		}

		#endregion

		#region GameObject2D implementation

		/// <summary>
		/// 	Update the tower for this frame
		/// </summary>
		/// <param name = "p_gameTime">snapshot of timing values</param>
		protected override void _Update(GameTime p_gameTime) {
			//update alarms
			m_alarm.Update(p_gameTime);

			//if attack is ready and tower has a target
			if(m_attackReady && m_currentTarget != null) {
				//fire at target and set alarm for next attack
				FireAtTarget();
				m_attackReady = false;
				m_alarm.Add(new AlarmObject(this, AttackDelay, "attackReady"));
			}

			//target change is possible every frame to ensure this tower is
			//attacking the target which is closest to the end of the path
			m_currentTarget = GameEngine.GetService<EnemyList>().FindTarget(m_position, AttackRange);
		}

		/// <summary>
		/// 	Draw the tower for this frame. Possible also drawing the attack
		/// 	radius if the tower is selected
		/// </summary>
		/// <param name = "p_gameTime">snapshot of timing values</param>
		protected override void _Draw(GameTime p_gameTime) {
			if(m_drawAttackRadius) {
				GameEngine.SpriteBatch.Draw(m_attackRadiusTexture, m_position + new Vector2(16), null, m_elementColor, 0.0f, new Vector2(m_attackRadiusTexture.Width / 2f, m_attackRadiusTexture.Height / 2f), AttackRange, SpriteEffects.None, 0.99f);
			}
			GameEngine.SpriteBatch.Draw(m_texture, m_position, null, m_textureTint, 0.0f, m_origin, m_scale, m_spriteEffects, m_zDepth);
		}

		#endregion
	}
}